import { join } from 'path'
import { MyDocumentFormattingEditProvider, delAllLineNote } from './format'
import { MyHoverProvider } from './hover'
import { MyCompletionItemProvider, MyCodeActionProvider, MyDefinitionProvider, MyReferenceProvider } from './auto'
import { MyDocumentSymbolProvider } from './symbol'
import { incrementSelection } from './incrementSelection'

import {
	LanguageClient,
	LanguageClientOptions,
	ServerOptions,
	TransportKind
} from 'vscode-languageclient/node'
import {
	workspace,
	ExtensionContext,
	commands,
	languages
} from 'vscode'

// 语言标识符常量
const LANGUAGE_ID = '4gl'
// 全局变量声明
let client: LanguageClient

/**
 * 插件激活函数
 * 当插件被激活时调用此函数
 * @param context 插件上下文
 */
export function activate(context: ExtensionContext) {

	// 命令注册组
	registerCommands(context)

	// 语言功能注册组
	registerLanguageProviders(context)

	// 设置语言服务器
	setupLanguageServer(context)
}

/**
 * 注册命令函数
 * 注册插件提供的所有命令
 * @param context 插件上下文
 */
function registerCommands(context: ExtensionContext): void {
	context.subscriptions.push(
		commands.registerCommand('my4gl.delAllLineNote', delAllLineNote),
		commands.registerCommand('my4gl.incrementSelection', incrementSelection)
	)
}

/**
 * 注册语言提供者函数
 * 注册插件提供的所有语言功能
 * @param context 插件上下文
 */
function registerLanguageProviders(context: ExtensionContext): void {
	context.subscriptions.push(
		languages.registerCompletionItemProvider(LANGUAGE_ID, new MyCompletionItemProvider()),
		languages.registerDocumentFormattingEditProvider(LANGUAGE_ID, new MyDocumentFormattingEditProvider()),
		languages.registerHoverProvider(LANGUAGE_ID, new MyHoverProvider()),
		languages.registerCodeActionsProvider(LANGUAGE_ID, new MyCodeActionProvider()),
		languages.registerDocumentSymbolProvider(LANGUAGE_ID, new MyDocumentSymbolProvider()),
		languages.registerDefinitionProvider(LANGUAGE_ID, new MyDefinitionProvider()),
		languages.registerReferenceProvider(LANGUAGE_ID, new MyReferenceProvider())
	)
}

/**
 * 设置语言服务器函数
 * 配置并启动语言服务器
 * @param context 插件上下文
 */
function setupLanguageServer(context: ExtensionContext): void {
	const serverModule = context.asAbsolutePath(join('server', 'out', 'server.js'))
	
	const serverOptions: ServerOptions = {
		run: { module: serverModule, transport: TransportKind.ipc },
		debug: { module: serverModule, transport: TransportKind.ipc }
	}

	const clientOptions: LanguageClientOptions = {
		documentSelector: [{ scheme: 'file', language: LANGUAGE_ID }],
		synchronize: {
			fileEvents: workspace.createFileSystemWatcher('**/.clientrc')
		}
	}

	client = new LanguageClient('languageServer', 'Language Server', serverOptions, clientOptions)
	client.start()
}

/**
 * 插件停用函数
 * 当插件被停用时调用此函数
 * @returns Promise<void> 或 undefined
 */
export function deactivate(): Thenable<void> | undefined {
	if (!client) {
		return undefined
	}
	return client.stop()
}